/*
 * Copyright (C) Michael Opitz
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA
 */
#ifndef TCP_SOCKET_H
#define TCP_SOCKET_H

#include "i_socket.h"

#include "socket/socket.h"
#include "socket/throwing_error_policy.h"
#include "socket/blocking_policy.h"
#include "socket/no_locking_policy.h"

#include <boost/shared_ptr.hpp>

typedef network::socket<
		network::blocking_policy, 
		network::no_locking_policy,
		network::throwing_error_policy
	> tcp_sock_impl;

/** 
 * \brief This namespaces includes all nertwork related stuff.
 * \author Michael Opitz
 */
namespace network {
	/** 
	 * \brief This class represents a tcp-socket.
	 */
	class tcp_socket : public network::i_socket {
	public:
		/** 
		 * \brief tcp_socket creates a tcp-socket from a tcp_sock_impl.
		 * 
		 * \param impl is a tcp_sock_impl object)
		 */
		tcp_socket(boost::shared_ptr<tcp_sock_impl> impl):_impl(impl) {}
		/** 
		 * \brief tcp_socket creates a not connected socket, which can
		 * be bound to a local port.
		 */
		tcp_socket():_impl(new tcp_sock_impl()) {}
		/** 
		 * \brief tcp_socket creates a tcp-socket.
		 * 
		 * \param addr is the ip-address to which you want to connect.
		 * \param port is the port to which you want to connect.
		 */
		tcp_socket(const string &addr, int port) 
		{
			_impl.reset(new tcp_sock_impl(addr, port));
		}
		virtual ~tcp_socket();

		/** 
		 * \brief send sends a string over the socket.
		 * 
		 * \param str is the string which should be send.
		 */
		virtual void send(const string &str);
		/** 
		 * \brief recv receives a string from the socket. Remember: this
		 * socket is a blocking socket!
		 * 
		 * \return a string is returned.
		 */
		virtual string recv();

		/** 
		 * \brief listen listenes to new connections.
		 * 
		 * \return true if a new connection was established
		 */
		virtual bool listen() const {return _impl->listen();}
		/** 
		 * \brief bind binds the socket to a local port
		 * 
		 * \param port is the port to which the socket should connect
		 * 
		 * \return true if the bind was successfull
		 */
		virtual bool bind(int port) {return _impl->bind(port);}
		/** 
		 * \brief accept accepts a new connection
		 * 
		 * \param sock is the socket of the new connection.
		 * 
		 * \return true if accept was successfull.
		 */
		virtual bool accept(tcp_socket &sock) 
		{
			return _impl->accept(*sock.get_impl());
		}

		/** 
		 * \brief get_impl returns the tcp_sock_impl of this socket.
		 * 
		 * \return a shared_ptr to the tcp_sock_impl-object
		 */
		boost::shared_ptr<tcp_sock_impl> get_impl() {return _impl;}
	private:
		boost::shared_ptr<tcp_sock_impl> _impl;
	};
}

#endif
